package com.hqd.ch03.v30.factory.support;

import com.hqd.ch03.v30.beans.Mergeable;

import java.util.LinkedHashMap;
import java.util.Map;

public class ManagedMap<K, V> extends LinkedHashMap<K, V> implements Mergeable {


    private Object source;


    private String keyTypeName;


    private String valueTypeName;

    private boolean mergeEnabled;


    public ManagedMap() {
    }

    public ManagedMap(int initialCapacity) {
        super(initialCapacity);
    }


    @SafeVarargs
    public static <K, V> ManagedMap<K, V> ofEntries(Map.Entry<? extends K, ? extends V>... entries) {
        ManagedMap<K, V> map = new ManagedMap<>();
        for (Map.Entry<? extends K, ? extends V> entry : entries) {
            map.put(entry.getKey(), entry.getValue());
        }
        return map;
    }


    public String getKeyTypeName() {
        return this.keyTypeName;
    }

    /**
     * Set the default key type name (class name) to be used for this map.
     */
    public void setKeyTypeName(String keyTypeName) {
        this.keyTypeName = keyTypeName;
    }

    public String getValueTypeName() {
        return this.valueTypeName;
    }

    public void setValueTypeName(String valueTypeName) {
        this.valueTypeName = valueTypeName;
    }

    @Override
    public boolean isMergeEnabled() {
        return this.mergeEnabled;
    }

    public void setMergeEnabled(boolean mergeEnabled) {
        this.mergeEnabled = mergeEnabled;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object merge(Object parent) {
        if (!this.mergeEnabled) {
            throw new IllegalStateException("Not allowed to merge when the 'mergeEnabled' property is set to 'false'");
        }
        if (parent == null) {
            return this;
        }
        if (!(parent instanceof Map)) {
            throw new IllegalArgumentException("Cannot merge with object of type [" + parent.getClass() + "]");
        }
        Map<K, V> merged = new ManagedMap<>();
        merged.putAll((Map<K, V>) parent);
        merged.putAll(this);
        return merged;
    }

}
